package com.newfiber.business.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.newfiber.business.domain.PatrolLog;
import com.newfiber.business.domain.PatrolPathStay;
import com.newfiber.business.domain.request.patrolPath.PatrolPathSaveRequest;
import com.newfiber.business.domain.request.patrolPathStay.PatrolPathStayQueryRequest;
import com.newfiber.business.domain.request.patrolPathStay.PatrolPathStaySaveRequest;
import com.newfiber.business.domain.request.patrolPathStay.PatrolPathStayUpdateRequest;
import com.newfiber.business.enums.EPatrolConfig;
import com.newfiber.business.enums.EPatrolPathRefType;
import com.newfiber.business.enums.EPatrolRedisKey;
import com.newfiber.business.mapper.PatrolPathStayMapper;
import com.newfiber.business.service.IPatrolLogService;
import com.newfiber.business.service.IPatrolPathStayService;
import com.newfiber.common.core.exception.ServiceException;
import com.newfiber.common.core.geometry.GeometryUtils;
import com.newfiber.common.core.web.domain.BaseEntity;
import com.newfiber.common.core.web.service.BaseServiceImpl;

import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import com.newfiber.common.redis.service.RedisService;
import com.newfiber.common.security.utils.ConfigUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Polygon;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 巡查轨迹停留记录Service业务层处理
 *
 * @author X.K
 * @date 2023-03-08
 */
@Service
public class PatrolPathStayServiceImpl extends BaseServiceImpl<PatrolPathStayMapper, PatrolPathStay> implements IPatrolPathStayService {

    @Resource
    private PatrolPathStayMapper patrolPathStayMapper;

    @Resource
    private IPatrolLogService patrolLogService;

    @Resource
    private RedisService redisService;

    @Override
    public long insert(PatrolPathStaySaveRequest request) {
        PatrolPathStay patrolPathStay = new PatrolPathStay();
        BeanUtils.copyProperties(request, patrolPathStay);
        save(patrolPathStay);
        return Optional.of(patrolPathStay).map(BaseEntity::getId).orElse(0L);
    }

    @Override
    public long insert(EPatrolPathRefType refType, Long refId, Long userId, String stayLonLat, Date stayDatetime, Double stayDuration) {
        PatrolPathStay patrolPathStay = new PatrolPathStay();
        patrolPathStay.setRefType(refType.getCode());
        patrolPathStay.setRefId(refId);
        patrolPathStay.setUserId(userId);
        patrolPathStay.setStayLonLat(stayLonLat);
        patrolPathStay.setStayDatetime(stayDatetime);
        patrolPathStay.setStayDuration(stayDuration);
        save(patrolPathStay);
        return Optional.of(patrolPathStay).map(BaseEntity::getId).orElse(0L);
    }

    @Override
    public boolean update(PatrolPathStayUpdateRequest request) {
        PatrolPathStay patrolPathStay = new PatrolPathStay();
        BeanUtils.copyProperties(request, patrolPathStay);
        return updateById(patrolPathStay);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(String ids) {
        return deleteLogic(ids);
    }

    @Override
    public long patrolStayUserDistinctCount() {
        QueryWrapper<PatrolPathStay> queryWrapper = new QueryWrapper<PatrolPathStay>().select("distinct user_id");
        return count(queryWrapper);
    }

    @Override
    public PatrolPathStay selectDetail(Long id) {
        PatrolPathStay patrolPathStay = patrolPathStayMapper.selectById(id);
        if (null == patrolPathStay) {
            throw new ServiceException(String.format("%s ID=%s 的记录不存在", this.getClass().getSimpleName(), id));
        }
        patrolPathStay.setPatrolPath(patrolLogService.getPatrolPath(patrolPathStay.getRefId()));
        return patrolPathStay;
    }

    @Override
    public List<PatrolPathStay> selectPage(PatrolPathStayQueryRequest request) {
        return patrolPathStayMapper.selectByCondition(request);
    }

    @Override
    public List<PatrolPathStay> selectList(PatrolPathStayQueryRequest request) {
        return patrolPathStayMapper.selectByCondition(request);
    }

    @Override
    public void calcPatrolStay() {
        Collection<String> patrolLogIdList = redisService.keys(EPatrolRedisKey.PatrolPath);
        if (CollectionUtils.isEmpty(patrolLogIdList)) {
            return;
        }
        patrolLogIdList = patrolLogIdList.stream().map(t -> t.split(":")[1]).distinct().collect(Collectors.toList());

        long patrolStayRadius = Long.parseLong(ConfigUtils.getConfig(EPatrolConfig.PatrolStayRadius.getCode()).toString());
        for (String patrolLogId : patrolLogIdList) {
            Collection<String> patrolPathStringList = redisService.mGet(EPatrolRedisKey.PatrolPath, patrolLogId);
            if (CollectionUtils.isEmpty(patrolPathStringList)) {
                return;
            }

            // TODO 半小时内巡查轨迹
            Date halfHourAgo = DateUtil.offsetMinute(new Date(), -30);
            List<PatrolPathSaveRequest> allPathList = patrolPathStringList.stream().map(
                            t -> JSONObject.parseObject(t, PatrolPathSaveRequest.class)).filter(t -> t.getPatrolDatetime().after(halfHourAgo)).
                    sorted(Comparator.comparing(PatrolPathSaveRequest::getPatrolDatetime)).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(allPathList)) {
                continue;
            }

            // 起始点
            PatrolPathSaveRequest startPath = allPathList.get(0);

            // 巡查轨迹
            List<Coordinate> coordinateList = allPathList.stream().map(t -> new Coordinate(t.parseLon(), t.parseLat())).collect(Collectors.toList());
            LineString lineString = GeometryUtils.createLineString(coordinateList);

            // 缓冲区范围
            Polygon polygon = GeometryUtils.createCircle(startPath.parseLon(), startPath.parseLat(), patrolStayRadius);

            // 轨迹和缓冲区是否相交，不相交则停留
            boolean intersectionFlag = GeometryUtils.judgeIntersection(polygon, lineString);
            if (intersectionFlag) {
                PatrolLog patrolLog = patrolLogService.selectDetailBrief(Long.parseLong(patrolLogId));
                if (null != patrolLog) {
                    insert(EPatrolPathRefType.PatrolLog, Long.parseLong(patrolLogId), patrolLog.getLogUserId(), startPath.getLonLat(), startPath.getPatrolDatetime(), 0.5);
                }
            }
        }

    }

}
